package {
	import flash.desktop.*;
	import flash.display.*;
	import flash.events.*;
	import flash.geom.*;
	import flash.media.*;
	import flash.text.*;
	import flash.ui.*;
	import flash.utils.*;
	import flash.net.*;
	public class Game extends Sprite {
		//[Embed(source="../art/template.png")]
		//private static const Template: Class;
		[Embed(source="../art/segment_01.png")]
		private static const Segment1: Class;
		[Embed(source="../art/segment_02.png")]
		private static const Segment2: Class;
		[Embed(source="../art/segment_03.png")]
		private static const Segment3: Class;
		[Embed(source="../art/segment_04.png")]
		private static const Segment4: Class;
		[Embed(source="../art/segment_05.png")]
		private static const Segment5: Class;
		[Embed(source="../art/segment_06.png")]
		private static const Segment6: Class;
		
		[Embed(source="../art/husk_01.png")]
		private static const Husk1: Class;
		[Embed(source="../art/husk_02.png")]
		private static const Husk2: Class;
		[Embed(source="../art/husk_03.png")]
		private static const Husk3: Class;
		[Embed(source="../art/husk_04.png")]
		private static const Husk4: Class;
		[Embed(source="../art/husk_05.png")]
		private static const Husk5: Class;
		[Embed(source="../art/husk_06.png")]
		private static const Husk6: Class;
		
		[Embed(source="../art/map_01.png")]
		private static const Map1: Class;
		[Embed(source="../art/map_02.png")]
		private static const Map2: Class;
		[Embed(source="../art/map_03.png")]
		private static const Map3: Class;
		[Embed(source="../art/map_04.png")]
		private static const Map4: Class;
		[Embed(source="../art/map_05.png")]
		private static const Map5: Class;
		[Embed(source="../art/map_06.png")]
		private static const Map6: Class;
		
		[Embed(source="../art/scene_color_01.png")]
		private static const SceneColor1: Class;
		[Embed(source="../art/scene_color_02.png")]
		private static const SceneColor2: Class;
		[Embed(source="../art/scene_color_03.png")]
		private static const SceneColor3: Class;
		[Embed(source="../art/scene_color_04.png")]
		private static const SceneColor4: Class;
		[Embed(source="../art/scene_color_05.png")]
		private static const SceneColor5: Class;
		[Embed(source="../art/scene_color_06.png")]
		private static const SceneColor6: Class;
		
		[Embed(source="../art/head1.png")]
		private static const Head1: Class;
		[Embed(source="../art/head2.png")]
		private static const Head2: Class;
		[Embed(source="../art/head3.png")]
		private static const Head3: Class;
		[Embed(source="../art/head4.png")]
		private static const Head4: Class;
		
		[Embed("../maps/map1.txt", mimeType="application/octet-stream")]
		private static const Map1Class : Class;
		private static var mapString1: String = new Map1Class().toString();
		[Embed("../maps/map2.txt", mimeType="application/octet-stream")]
		private static const Map2Class : Class;
		private static var mapString2: String = new Map2Class().toString();
		[Embed("../maps/map3.txt", mimeType="application/octet-stream")]
		private static const Map3Class : Class;
		private static var mapString3: String = new Map3Class().toString();
		[Embed("../maps/map4.txt", mimeType="application/octet-stream")]
		private static const Map4Class : Class;
		private static var mapString4: String = new Map4Class().toString();
		[Embed("../maps/map5.txt", mimeType="application/octet-stream")]
		private static const Map5Class : Class;
		private static var mapString5: String = new Map5Class().toString();
		[Embed("../maps/map6.txt", mimeType="application/octet-stream")]
		private static const Map6Class : Class;
		private static var mapString6: String = new Map6Class().toString();
		
		[Embed(source="../art/control.png")]
		private static const ControlImage: Class;
		
		[Embed(source="../song.mp3")]
		private static var SongClass: Class;
		private static var song: Sound = new SongClass() as Sound;
		
		private var container: IsoContainer;
		private var map: Array;
		private var container2: IsoContainer;
		private var map2: Array;
		private var cursor: IsoSprite;
		private var cursorURL: String = "template.png";
		private var cursorDX: int;
		private var cursorDY: int;
		private var levelNames: Array = ["map1.txt", "map2.txt", "map3.txt", "map4.txt", "map5.txt", "map6.txt"];
		private var levels: Array = [];
		//private var levels: Array = [mapString1, mapString2, mapString3, mapString4, mapString5, mapString6];
		private var currentLevel: int;
		private var prevLevel: int;
		private var nextLevel: int;
		private var levelHistory: Array = [[], [], [], []];
		private var levelBlockHistory: Array = [[], [], [], []];
		private var hexagon: DisplayObject;
		
		private var mapsLoaded: int = levels.length;
		[Bindable]
		public var mapData: String;
		
		private var gameTime: Number;
		private var accumulator: Number;
		private var prevTicks: int;
		private var timeSinceLevel: Number;
		
		public var prevHusk: Class;
		public var curSegment: Class;
		public var curHusk: Class;
		
		public function Game(stage: Stage) {
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyPressed);
			stage.addEventListener(Event.ENTER_FRAME, onTimer);
			
			loadNextMap(null);
		}
		
		private function loadNextMap(event: Event): void {
			if (event != null) {
				var eventLoader: URLLoader = event.target as URLLoader;
				levels[mapsLoaded] = eventLoader.data;
				mapsLoaded++;
			}
			
			if (mapsLoaded == levelNames.length) {
				currentLevel = 0;
				findPrevLevel();
				startMap();
				
				var controlImage: DisplayObject = new ControlImage();
				controlImage.x = 640;
				controlImage.y = 400;
				addChild(controlImage);
				
				accumulator = 0;
				gameTime = 0;
				prevTicks = getTimer();
				song.play(0,99999);
				return;
			}
			
			var loader: URLLoader = new URLLoader(new URLRequest("maps/" + levelNames[mapsLoaded]));
			loader.addEventListener(Event.COMPLETE, loadNextMap);
			loader.dataFormat = URLLoaderDataFormat.TEXT;
		}
		
		private function findPrevLevel(): void {
			prevLevel = (currentLevel + levelNames.length - 1) % levelNames.length;
			nextLevel = (currentLevel + 1) % levelNames.length;
			curSegment = Game["Segment" + (1 + currentLevel)];
			prevHusk = Game["Husk" + (1 + prevLevel)];
			curHusk = Game["Husk" + (1 + currentLevel)];
		}
		
		private function updateCursor(): void {
			if (cursor == null) return;
			while(cursor.numChildren > 0) cursor.removeChildAt(0);
			var bitmap: Bitmap;
			if (cursorDX == -1) {
				bitmap = new Head2();
			} else if (cursorDX == 1) {
				bitmap = new Head4();
			} else if (cursorDY == -1) {
				bitmap = new Head1();
			} else if (cursorDY == 1) {
				bitmap = new Head3();
			}
			if (bitmap == null) return;
			bitmap.x = -bitmap.width / 2;
			bitmap.y = -bitmap.height / 2;
			cursor.addChild(bitmap);
		}
		
		private function onKeyPressed(event: KeyboardEvent): void {
			//trace(event.keyCode, String.fromCharCode(event.charCode));
			if (stage.focus != stage) return;
			//if (event.ctrlKey)
			switch (event.keyCode) {
				case 32: // space
					if (timeSinceLevel <= 1.1 && currentLevel > 0) {
						currentLevel = prevLevel;
						findPrevLevel();
					}
					startMap();
					break;
				case 81: // q
					cursorDX = -1;
					cursorDY = 0;
					updateCursor();
					break;
				case 87: // w
					cursorDX = 0;
					cursorDY = -1;
					updateCursor();
					break;
				case 65: // a
					cursorDX = 0;
					cursorDY = 1;
					updateCursor();
					break;
				case 83: // s
					cursorDX = 1;
					cursorDY = 0;
					updateCursor();
					break;
					break;
					/*
				case 38: // up
					cursor.iy--;
					break;
				case 40: // down
					cursor.iy++;
					break;
				case 37: // left
					cursor.ix--;
					break;
				case 39: // right
					cursor.ix++;
					break;
				case 188: // <
					cursor.iz--;
					break;
				case 190: // >
					cursor.iz++;
					break;
				case 32: // space
					addBlockAt(cursor.ix, cursor.iy, cursor.iz, cursorURL);
					mapData += cursorURL + "\n";
					mapData += "\t" + cursor.ix + " " + cursor.iy + " " + cursor.iz + "\n";
					break;
				case 8: // delete
					addBlockAt(cursor.ix, cursor.iy, cursor.iz, null);
					mapData += "empty\n";
					mapData += "\t" + cursor.ix + " " + cursor.iy + " " + cursor.iz + "\n";
					break;*/
			}
		}
		
		public function setBlockURL(url: String): void {
			cursorURL = url;
		}
		
		private function onTimer(event: Event): void {
			if (cursor == null) return;
			
			var curTicks: int = getTimer();
			var deltaTicks: int = curTicks - prevTicks;
			prevTicks = curTicks;
			accumulator += deltaTicks * .001; // convert from milliseconds to seconds
			
			var framePassed: Boolean = false;
			while (accumulator >= 0.5) {
				framePassed = true;
				accumulator -= 0.5;
				timeSinceLevel += 0.5;
			}
			
			if (!framePassed) return;
			
			var history: Array = levelHistory[currentLevel];
			var blockHistory: Array = levelBlockHistory[currentLevel];
			var prevStep: Array = history.length > 0 ? history[history.length - 1] : null;
			if (prevStep != null && prevStep[0] == cursor.ix + cursorDX && prevStep[1] == cursor.iy + cursorDY) {
				cursor.ix = prevStep[0];
				cursor.iy = prevStep[1];
				cursor.iz = prevStep[2];
				//addBlockAt(prevStep[0], prevStep[1], prevStep[2], null);
				history.pop();
				//blockHistory.pop();
				while (true) {
					var blockCoords: Array = blockHistory[blockHistory.length-1];
					addBlockAt(blockCoords[0], blockCoords[1], blockCoords[2], null, false);
					addBlockAt(blockCoords[0], blockCoords[1], blockCoords[2], null, true);
					blockHistory.pop();
					if (cursor.ix == blockCoords[0] && cursor.iy == blockCoords[1] && cursor.iz == blockCoords[2]) {
						break;
					}
				}
				if (cursor.ix == 0) {
					if (currentLevel > 0) {
						currentLevel = prevLevel;
						findPrevLevel();
					}
					startMap();
				}
			} else {
				var originalX: int = cursor.ix;
				var originalY: int = cursor.iy;
				addBlockAt(cursor.ix, cursor.iy, cursor.iz, curSegment, false);
				addBlockAt(cursor.ix, cursor.iy, cursor.iz, curHusk, true);
				history.push([cursor.ix, cursor.iy, cursor.iz]);
				blockHistory.push([cursor.ix, cursor.iy, cursor.iz]);
				cursor.ix += cursorDX;
				cursor.iy += cursorDY;
				if (cursor.ix < 0 || cursor.ix > 9 || cursor.iy > 9 || cursor.iz > 7) {
					startMap();
					return;
				} else if (map[cursor.ix][cursor.iy][cursor.iz] is IsoSprite) {
					for each (prevStep in history) {
						if (prevStep[0] == cursor.ix && prevStep[1] == cursor.iy && prevStep[2] == cursor.iz) {
							startMap();
							return;
						}
					}
					if (map[cursor.ix][cursor.iy][cursor.iz+1] is IsoSprite) {
						startMap();
						return;
					} else {
						cursor.iz++;
						addBlockAt(originalX, originalY, cursor.iz, curSegment, false);
						addBlockAt(originalX, originalY, cursor.iz, curHusk, true);
						blockHistory.push([originalX, originalY, cursor.iz]);
					}
				} else {
					while (map[cursor.ix][cursor.iy][cursor.iz-1] == null) {
						addBlockAt(cursor.ix, cursor.iy, cursor.iz, curSegment, false);
						addBlockAt(cursor.ix, cursor.iy, cursor.iz, curHusk, true);
						blockHistory.push([cursor.ix, cursor.iy, cursor.iz]);
						cursor.iz--;
					}
				}
			}
			
			if (cursor.iy == 0) {
				currentLevel = (currentLevel + 1) % levelNames.length;
				findPrevLevel();
				startMap();
			}
			//backward_loop.play();
		}
		
		private function startMap(): void {
			var i: int;
			var j: int;
			var k: int;
			
			if (container != null) {
				removeChild(container);
			}
			
			container = new IsoContainer();
			addChild(container);
			container.x = Main.WIDTH / 2;
			container.y = Main.HEIGHT / 2;
			container.scaleX = container.scaleY = 2;
			
			container2 = new IsoContainer();
			addChild(container2);
			container2.x = Main.WIDTH * 5 / 4;
			container2.y = Main.HEIGHT / 2;
		    container2.transform.colorTransform = new ColorTransform(0.5, 0.5, 0.5);
			
			map = [];
			for (i = 0; i < 30; i++) {
				var imap: Array = [];
				map.push(imap);
				for (j = 0; j < 30; j++) {
					var jmap: Array = [];
					imap.push(jmap);
					for (k = 0; k < 30; k++) {
						jmap.push(null);
					}
				}
			}
			
			map2 = [];
			for (i = 0; i < 30; i++) {
				var imap2: Array = [];
				map2.push(imap2);
				for (j = 0; j < 30; j++) {
					var jmap2: Array = [];
					imap2.push(jmap2);
					for (k = 0; k < 30; k++) {
						jmap2.push(null);
					}
				}
			}
			
			parseMap(false);
			parseMap(true);
			
			var foundExit: Boolean = false;
			for (j = 0; j < 8; j++) {
				for (i = 0; i < 10; i++) {
					if (map[0][i][j] == null) {
						foundExit = true;
						break;
					}
				}
				if (foundExit) break;
			}
			
			for each (var coords: Array in levelBlockHistory[prevLevel]) {
				addBlockAt(coords[0], coords[1], coords[2], prevHusk, false);
			}
			
			if (hexagon != null) removeChild(hexagon);
			hexagon = new Game["Map" + (1 + currentLevel)]();
			hexagon.scaleX = hexagon.scaleY = 2;
			addChild(hexagon);
			hexagon.y = 420;
			
			cursor = new IsoSprite();
			cursor.ix = 0;
			cursor.iy = i;
			cursor.iz = j;
			container.addIsoSprite(cursor);
			cursorDX = 1;
			cursorDY = 0;
			updateCursor();
			
			levelHistory[currentLevel] = [];
			levelBlockHistory[currentLevel] = [];
			
			timeSinceLevel = 0;
		}
		
		private function parseMap(useNextLevel: Boolean): void {
			var i: int;
			var j: int;
			var k: int;
			var lines: Array = levels[useNextLevel ? nextLevel : currentLevel].split("\n");
			var url: *;
			for each (var line: String in lines) {
				if (line.charAt(0) == "\t") {
					var args: Array = line.substr(1).split(" ");
					if (args.length < 3) {
						continue;
					}
					var x1: int = parseInt(args[0]);
					var y1: int = parseInt(args[1]);
					var z1: int = parseInt(args[2]);
					if (args.length >= 7 && args[3] == "-") {
						var x2: int = parseInt(args[4]);
						var y2: int = parseInt(args[5]);
						var z2: int = parseInt(args[6]);
						var dx: int = x2 < x1 ? -1 : 1;
						var dy: int = y2 < y1 ? -1 : 1;
						var dz: int = z2 < z1 ? -1 : 1;
						for (i = x1; i != x2 + dx; i += dx) {
							for (j = y1; j != y2 + dy; j += dy) {
								for (k = z1; k != z2 + dz; k += dz) {
									addBlockAt(i, j, k, url, useNextLevel);
								}
							}
						}
					} else {
						addBlockAt(x1, y1, z1, url, useNextLevel);
					}
				} else {
					if (line.indexOf("empty") != -1) {
						url = null;
					} else if (line.indexOf("template.png") != -1) {
						url = Game["SceneColor" + (1 + (useNextLevel ? nextLevel : currentLevel))];
					} else {
						url = line;
						trace(url);
					}
				}
			}
		}
		
		public function addBlockAt(ix: int, iy: int, iz: int, url: *, useNextLevel: Boolean, useGradient: Boolean = true): void {
			var mapUsed: Array = useNextLevel ? map2 : map;
			var containerUsed: IsoContainer = useNextLevel ? container2 : container;
			if (mapUsed[ix][iy][iz] != null) {
				containerUsed.removeIsoSprite(mapUsed[ix][iy][iz]);
				mapUsed[ix][iy][iz] = null;
			}
			
			if (url != null) {
				var block: IsoSprite = new IsoSprite();
				if (url is String) {
					var loader: Loader = new Loader();
					loader.load(new URLRequest("art/"+ url));
					loader.x = -16;
					loader.y = -16;
					block.addChild(loader);
				} else if (url is Class) {
					var bitmap: Bitmap = new url();
					bitmap.x = -bitmap.width / 2;
					bitmap.y = -bitmap.height / 2;
					block.addChild(bitmap);
				}
				
				if (useGradient) {
					var brightness: Number = 1 + (iz - 2) / 5;
		            block.transform.colorTransform = new ColorTransform(brightness, brightness, brightness);
				}
				
				block.ix = ix;
				block.iy = iy;
				block.iz = iz;
				
				containerUsed.addIsoSprite(block);
				mapUsed[ix][iy][iz] = block;
			}
		}
	}
}